package org.elastic.compreplatform.redis.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.elastic.compreplatform.common.constant.RespEnum;
import org.elastic.compreplatform.common.model.PageHelper;
import org.elastic.compreplatform.common.model.RespMsg;
import org.elastic.compreplatform.common.model.SysFile;
import org.elastic.compreplatform.common.service.impl.SysFileServiceImpl;
import org.elastic.compreplatform.common.util.DateUtil;
import org.elastic.compreplatform.common.util.PageHelperUtil;
import org.elastic.compreplatform.common.util.RespMsgUtil;
import org.elastic.compreplatform.common.util.SeqUtil;
import org.elastic.compreplatform.common.vo.query.SysFileQuery;
import org.elastic.compreplatform.redis.core.factory.JedisConnectionFactory;
import org.elastic.compreplatform.redis.model.CacheModel;
import org.elastic.compreplatform.redis.model.RedisModel;
import org.elastic.compreplatform.redis.service.RedisServiceImpl;
import org.elastic.compreplatform.redis.util.JedisUtil;
import org.elastic.compreplatform.redis.util.OrderProperties;
import org.elastic.compreplatform.redis.vo.query.RedisQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.github.pagehelper.Page;

import redis.clients.jedis.JedisPool;

/**
 * ClassName: RedisController 
 * @Description: redis控制层
 * @author JornTang
 * @date 2018年2月28日
 */
@Controller
@RequestMapping("/redis")
public class RedisController {
	private static Logger log = LoggerFactory.getLogger(RedisController.class);
	@Resource
	private RedisServiceImpl redisService;
	@Resource
	private SysFileServiceImpl sysFileService;
	/**
	 * @Description: 进入备份列表
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月4日
	 */
	@RequestMapping("/toBackupDatabase")
	public String toBackupDatabase(Model model) {
		//获取所有数据库配置
		EntityWrapper<RedisModel> wrapper = new EntityWrapper<RedisModel>();
		wrapper.where("db_type = {0}", "redis");
		List<RedisModel> list = redisService.selectList(wrapper);
		model.addAttribute("list", list);
		return "redis/backup-list";
	}
	/**
	 * @Description: 分页查询备份列表
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月4日
	 */
	@RequestMapping("/backupPageList")
	@ResponseBody
	public PageHelper backupPageList(HttpServletRequest request, HttpServletResponse response, SysFileQuery query, PageHelper page) {
		query.setFileType("redis.rdb");
		Page<SysFile> list = sysFileService.pagelist(query, page);
        return PageHelperUtil.doHandlePage(list);
	}
	/**
	 * @Description: redis备份
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月4日
	 */
	@RequestMapping("/backupDatabase")
	@ResponseBody
	public RespMsg backupDatabase(HttpServletRequest request, HttpServletResponse response, SysFileQuery query, CacheModel cache) {
		RespMsg msg = RespMsgUtil.returnMsg(RespEnum.SUCCESS);
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
			JedisUtil.backupDatabase(redisModel);
		} catch (Exception e) {
			msg = RespMsgUtil.returnMsg(RespEnum.ERROR);
			log.error("清理所有缓存数据异常", e);
		}
		return msg;
	}
	/** 
	 * 进入缓存监控报表页面
	 **/
	@RequestMapping("/toCacheChart")
	public String toCacheChart(Model model, CacheModel cache) {
		try {
			//获取所有数据库配置
			EntityWrapper<RedisModel> wrapper = new EntityWrapper<RedisModel>();
			wrapper.where("db_type = {0}", "redis");
			List<RedisModel> list = redisService.selectList(wrapper);
			model.addAttribute("list", list);
			model.addAttribute("cache", cache);
		} catch (Exception e) {
			log.error("进入缓存监控报表页面异常", e);
		}
		return "redis/cache-chart";
	}
	/**
	 * @Description: 异步加载图表信息
	 * @param cache
	 * @return   
	 * @return List<Map<String,Object>>  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月2日
	 */
	@RequestMapping("/loadAsyncChart")
	@ResponseBody
	public Map<String, Object> loadAsyncChart(CacheModel cache){
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
		    String jedisInfo = JedisUtil.getJedisInfo(redisModel);
		    //构造图表信息
		    return doJedisChartInfo(jedisInfo);
		} catch (Exception e) {
			log.error("异步加载图表信息异常", e);
		}
		return null;
	}
	/**
	 * @Description: 清理所有缓存数据
	 * @param cache
	 * @return   
	 * @return respMsg  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	@RequestMapping("/flushAll")
	@ResponseBody
	public RespMsg flushAll(CacheModel cache) {
		RespMsg msg = RespMsgUtil.returnMsg(RespEnum.SUCCESS);
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
			JedisUtil.flushAll(redisModel);
		} catch (Exception e) {
			msg = RespMsgUtil.returnMsg(RespEnum.ERROR);
			log.error("清理所有缓存数据异常", e);
		}
		return msg;
	}
	/**
	 * @Description: 清理指定库缓存数据
	 * @param cache
	 * @return   
	 * @return respMsg  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月1日
	 */
	@RequestMapping("/flushDb")
	@ResponseBody
	public RespMsg flushDb(CacheModel cache) {
		RespMsg msg = RespMsgUtil.returnMsg(RespEnum.SUCCESS);
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
			JedisUtil.flushDb(redisModel, cache);
		} catch (Exception e) {
			msg = RespMsgUtil.returnMsg(RespEnum.ERROR);
			log.error("清理指定库缓存数据异常", e);
		}
		return msg;
	}
	/** 
	 * 删除缓存
	 **/
	@RequestMapping("/deleteKeys")
	@ResponseBody
	public RespMsg deleteKeys(CacheModel cache) {
		RedisModel redisModel = redisService.selectById(cache.getDbId());
		boolean isOk = JedisUtil.deleteKeys(redisModel, cache);
		return isOk?RespMsgUtil.returnMsg(RespEnum.SUCCESS): RespMsgUtil.returnMsg(RespEnum.ERROR);
	}
	/** 
	 * 进入缓存添加页面
	 **/
	@RequestMapping("/toCacheAdd")
	public String toCacheAdd(Model model, CacheModel cache) {
		model.addAttribute("cache", cache);
		return "redis/cache-add";
	}
	/** 
	 * 添加缓存
	 **/
	@RequestMapping("/cacheAdd")
	@ResponseBody
	public RespMsg cacheAdd(HttpServletRequest request, HttpServletResponse response, CacheModel cache) {
		RedisModel redisModel = redisService.selectById(cache.getDbId());
		boolean isOk = JedisUtil.saveForRedis(redisModel, cache);
		return isOk?RespMsgUtil.returnMsg(RespEnum.SUCCESS): RespMsgUtil.returnMsg(RespEnum.ERROR);
	}
	/** 
	 * 进入缓存修改页面
	 **/
	@RequestMapping("/toCacheUpdate")
	public String toCacheUpdate(Model model, CacheModel cache) {
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
			CacheModel cacheModel = JedisUtil.selectForRedis(redisModel, cache);
			model.addAttribute("cache", cacheModel);
		} catch (Exception e) {
			log.error("进入缓存修改页面异常", e);
		}
		return "redis/cache-update";
	}
	/**
	 * @Description: 进入缓存操作页面
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/toCache")
	public String toCache(Model model, Long dbId) {
		return "redis/cache-list";
	}
	/**
	 * @Description: 异步获取redis配置
	 * @return   
	 * @return List<RedisModel>  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/getAsyncRedisConf")
	@ResponseBody
	public List<RedisModel> getAsyncRedisConf() {
		//获取所有数据库配置
		EntityWrapper<RedisModel> wrapper = new EntityWrapper<RedisModel>();
		wrapper.where("db_type = {0}", "redis");
		return redisService.selectList(wrapper);
	}
	/**
	 * @Description: 异步获取redis database
	 * @return   
	 * @return List<RedisModel>  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/getAsyncDbForRedis")
	@ResponseBody
	public List<Map<String, Object>> getAsyncDbForRedis(Model model, Long dbId) {
		RedisModel redisModel = redisService.selectById(dbId);
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		//获取所有redis库
		int amount= JedisUtil.getAmountForRedis(redisModel);
		for (int i = 0; i < amount; i++) {
			Map<String, Object> db = new HashMap<String, Object>();
			db.put("id", i);
			db.put("name", "DB" + i);
			list.add(db);
		}
		return list;
	}
	/**
	 * @Description: 进入缓存操作页面
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/pageCache")
	@ResponseBody
	public PageHelper pageCache(Model model, Long dbId, Integer dbIndex, String cacheKey, PageHelper page) {
		RedisModel redisModel = redisService.selectById(dbId);
		JedisUtil.getPageForJedisCache(redisModel, dbIndex , cacheKey , page);
		return page;
	}
	/**
	 * @Description: 获取统计信息
	 * @return   
	 * @return String  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/toStat")
	public String toStat(Model model) {
		//获取所有数据库配置
		EntityWrapper<RedisModel> wrapper = new EntityWrapper<RedisModel>();
		wrapper.where("db_type = {0}", "redis");
		List<RedisModel> list = redisService.selectList(wrapper);
		model.addAttribute("list", list);
		return "redis/stat";
	}
	/**
	 * @Description: 分页获取统计信息
	 * @return   
	 * @return PageHelper  
	 * @throws
	 * @author JornTang
	 * @date 2018年2月28日
	 */
	@RequestMapping("/stat")
	@ResponseBody
	public PageHelper stat(Long dbId, PageHelper page) {
		try {
		    RedisModel redisModel = redisService.selectById(dbId);
		    String jedisInfo = JedisUtil.getJedisInfo(redisModel);
		    //构造分页
		    doJedisInfo(jedisInfo, page);
		} catch (Exception e) {
			log.error("redis分页获取统计信息异常", e);
		}
		return page;
	}
	/**
	 * @Description: 重置统计信息
	 * @return   
	 * @return RespMsg  
	 * @throws
	 * @author JornTang
	 * @date 2018年3月2日
	 */
	@RequestMapping("/clearInfo")
	@ResponseBody
	public RespMsg clearInfo(CacheModel cache) {
		RespMsg msg = RespMsgUtil.returnMsg(RespEnum.SUCCESS);
		try {
			RedisModel redisModel = redisService.selectById(cache.getDbId());
			JedisUtil.clearInfo(redisModel);
		} catch (Exception e) {
			msg = RespMsgUtil.returnMsg(RespEnum.ERROR);
			log.error("清理所有缓存数据异常", e);
		}
		return msg;
	}
	/**
	 * 构造统计信息
	 * @throws IOException 
	 */
	private void doJedisInfo(String jedisInfo, PageHelper page) throws IOException {
		if(StringUtils.isEmpty(jedisInfo)) {
			return;
		}
		//统计信息集合
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		OrderProperties properties = new OrderProperties();
	    InputStream inStream = new ByteArrayInputStream(jedisInfo.getBytes());
	    properties.load(inStream);
	    LinkedHashSet<Object> keys = (LinkedHashSet<Object>) properties.keySet();
	    Iterator<Object> iterator = keys.iterator();
	    int totalKeys = 0;
	    while (iterator.hasNext()) {
	      Map<String, Object> map = new HashMap<String, Object>();
	      String key = iterator.next() + "";
	      String value = properties.getProperty(key);
	      map.put("key", key);
	      /******************* server *********************/
	      if (key.equals("redis_version")) {
	        map.put("value", value);
	        map.put("content", "Redis 服务器版本");
	      } else if (key.equals("redis_mode")) {
	        map.put("value", value);
	        map.put("content", "运行模式");
	      } else if (key.equals("os")) {
	        map.put("value", value);
	        map.put("content", "Redis 服务器的宿主操作系统");
	      } else if (key.equals("arch_bits")) {
	        map.put("value", value);
	        map.put("content", "架构（32 或 64 位）");
	      } else if (key.equals("multiplexing_api")) {
	        map.put("value", value);
	        map.put("content", "Redis 所使用的事件处理机制");
	      } else if (key.equals("gcc_version")) {
	        map.put("value", value);
	        map.put("content", "编译 Redis 时所使用的 GCC 版本");
	      } else if (key.equals("tcp_port")) {
	        map.put("value", value);
	        map.put("content", "TCP/IP 监听端口");
	      } else if (key.equals("uptime_in_seconds")) {
	        map.put("value", value);
	        map.put("content", "自 Redis 服务器启动以来，经过的秒数");
	      } else if (key.equals("uptime_in_days")) {
	        map.put("value", value);
	        map.put("content", "自 Redis 服务器启动以来，经过的天数");
	      } else if (key.equals("config_file")) {
	        map.put("value", value);
	        map.put("content", "配置文件");
	      /******************* Clients *********************/
	      } else if (key.equals("connected_clients")) {
	        map.put("value", value);
	        map.put("content", "已连接客户端的数量（不包括通过从属服务器连接的客户端）");
	      } else if (key.equals("client_longest_output_list")) {
	        map.put("value", value);
	        map.put("content", "当前连接的客户端当中，最长的输出列表");
	      } else if (key.equals("client_biggest_input_buf")) {
	        map.put("value", value);
	        map.put("content", "当前连接的客户端当中，最大输入缓存");
	      } else if (key.equals("blocked_clients")) {
	        map.put("value", value);
	        map.put("content", "正在等待阻塞命令（BLPOP、BRPOP、BRPOPLPUSH）的客户端的数量");
	      /******************* Memory *********************/
	      } else if (key.equals("used_memory")) {
	        map.put("value", value);
	        map.put("content", "由 Redis 分配器分配的内存总量（以字节为单位）");
	      } else if (key.equals("used_memory_peak")) {
	        map.put("value", value);
	        map.put("content", "Redis 的内存消耗峰值（以字节为单位）");
	      /******************* Persistence *********************/
	      } else if (key.equals("aof_enabled")) {
	        map.put("value", value);
	        map.put("content", "是否开启了aof功能");
	      /******************* stats *********************/
	      } else if (key.equals("total_connections_received")) {
	        map.put("value", value);
	        map.put("content", "运行以来连接过的客户端的总数量");
	      } else if (key.equals("total_commands_processed")) {
	        map.put("value", value);
	        map.put("content", "运行以来执行过的命令的总数量");
	      } else if (key.equals("instantaneous_ops_per_sec")) {
	        map.put("value", value);
	        map.put("content", "每秒处理命令条数(TPS)");
	      } else if (key.equals("total_net_input_bytes")) {
	        map.put("value", value);
	        map.put("content", "输入网络流量（以字节为单位）");
	      } else if (key.equals("total_net_output_bytes")) {
	        map.put("value", value);
	        map.put("content", "输出网络流量（以字节为单位）");
	      } else if (key.equals("instantaneous_input_kbps")) {
	        map.put("value", value);
	        map.put("content", "每秒输入字节数");
	      } else if (key.equals("instantaneous_output_kbps")) {
	        map.put("value", value);
	        map.put("content", "每秒输出字节数");
	      } else if (key.equals("rejected_connections")) {
	        map.put("value", value);
	        map.put("content", "拒绝的连接个数(和maxclients这个配置有关)");
	      } else if (key.equals("sync_full")) {
	        map.put("value", value);
	        map.put("content", "主从完全同步成功次数");
	      } else if (key.equals("sync_partial_ok")) {
	        map.put("value", value);
	        map.put("content", "主从部分同步成功次数");
	      } else if (key.equals("sync_partial_err")) {
	        map.put("value", value);
	        map.put("content", "主从部分同步失败次数");
	      } else if (key.equals("expired_keys")) {
	        map.put("value", value);
	        map.put("content", "运行以来过期的 key 的数量");
	      } else if (key.equals("evicted_keys")) {
	        map.put("value", value);
	        map.put("content", "运行以来剔除(超过了maxmemory后)的 key 的数量");
	      } else if (key.equals("keyspace_hits")) {
	        map.put("value", value);
	        map.put("content", "命中次数");
	      } else if (key.equals("keyspace_misses")) {
	        map.put("value", value);
	        map.put("content", "不命中次数");
	      /******************* cpu *********************/
	      } else if (key.equals("used_cpu_sys")) {
	        map.put("value", value);
	        map.put("content", "将所有Redis主进程在核心态所占用的CPU时求和累计起来");
	      } else if (key.equals("used_cpu_user")) {
	        map.put("value", value);
	        map.put("content", "将所有Redis主进程在用户态所占用的CPU时求和累计起来");
	      } else if (key.equals("used_cpu_sys_children")) {
	        map.put("value", value);
	        map.put("content", "将后台进程在核心态所占用的CPU时求和累计起来");
	      } else if (key.equals("used_cpu_user_children")) {
	        map.put("value", value);
	        map.put("content", "将后台进程在用户态所占用的CPU时求和累计起来");
	      } else if (key.equals("cmdstat_get")) {
	        map.put("value", value);
	        map.put("content", "get命令调用次数,耗时，平均耗时(单位：微妙)");
	      } else if (key.equals("cmdstat_set")) {
	        map.put("value", value);
	        map.put("content", "set命令调用次数,耗时，平均耗时(单位：微妙)");
	      } else if (key.equals("last_save_time")) {
	        map.put("value", DateUtil.formatMillis(Long.parseLong(value + "000"), "yyyy-MM-dd hh:mm:ss"));
	        map.put("content", "上次保存RDB文件的时间");
	      } else {
	        map.put("value", value);
	        map.put("content", "");
	      }
	      if (key.indexOf("db") == 0) {
	          String ssi = value.substring(5, value.indexOf(","));
	          totalKeys += Integer.parseInt(ssi);
	      }
	      list.add(map);
	    }
	    Map<String, Object> totalKeysMap = new HashMap<String, Object>();
	    totalKeysMap.put("totalKeys", totalKeys);
	    list.add(totalKeysMap);
	    page.setCount(list.size());
	    page.setData(list);
	}
	/**
	 * @Description: 构造图表信息
	 * @return   
	 * @return List<Map<String,Object>>  
	 * @throws IOException 
	 * @throws
	 * @author JornTang
	 * @date 2018年3月2日
	 */
	public Map<String, Object> doJedisChartInfo(String jedisInfo) throws IOException{
		if(StringUtils.isEmpty(jedisInfo)) {
			return null;
		}
		//统计信息集合
		Map<String, Object> statMap = new HashMap<String, Object>();
		OrderProperties properties = new OrderProperties();
	    InputStream inStream = new ByteArrayInputStream(jedisInfo.getBytes());
	    properties.load(inStream);
	    LinkedHashSet<Object> keys = (LinkedHashSet<Object>) properties.keySet();
	    Iterator<Object> iterator = keys.iterator();
	    int totalKeys = 0;
	    while (iterator.hasNext()) {
	      String key = iterator.next() + "";
	      String value = properties.getProperty(key);
	      if (key.indexOf("db") == 0) {
	          String ssi = value.substring(5, value.indexOf(","));
	          totalKeys += Integer.parseInt(ssi);
	      }else {
	    	  statMap.put(key, value);
	      }
	    }
	    statMap.put("totalKeys", totalKeys);
	    return statMap;
	}
	/** 
	 * 测试连接
	 **/
	@RequestMapping("/checkConnection")
	@ResponseBody
	public RespMsg checkConnection(String dbUrl, Integer dbPort, String password) {
		RespMsg msg = RespMsgUtil.returnMsg(RespEnum.SUCCESS);
		try {
			JedisPool jedisPool = null;
			if(StringUtils.isEmpty(password)) {
				jedisPool = JedisConnectionFactory.buildJedisPool(dbUrl, dbPort, 3000);
			}else {
				jedisPool = JedisConnectionFactory.buildJedisPool(dbUrl, dbPort, 3000, password);
			}
			jedisPool.getResource();
		} catch (Exception e) {
			msg = RespMsgUtil.returnMsg(RespEnum.ERROR);
		}
		return msg;
	}
	/** 
	 * 进入列表页面
	 **/
	@RequestMapping("/toList")
	public String toList(Model model) {
		return "redis/list";
	}
	/** 
	 * 分页查询
	 **/
	@RequestMapping("/pageList")
	@ResponseBody
	public PageHelper pagelist(HttpServletRequest request, HttpServletResponse response, RedisQuery query, PageHelper page) {
		Page<RedisModel> list = redisService.pagelist(query, page);
        return PageHelperUtil.doHandlePage(list);
	}
	/** 
	 * 进入添加页面
	 **/
	@RequestMapping("/toAdd")
	public String toAdd(Model model) {
		return "redis/add";
	}
	/** 
	 * 添加
	 **/
	@RequestMapping("/add")
	@ResponseBody
	public RespMsg add(HttpServletRequest request, HttpServletResponse response, Model model, RedisModel entity) {
		entity.setId(SeqUtil.getSeq());
		boolean isOK = redisService.insert(entity);
		return isOK?RespMsgUtil.returnMsg(RespEnum.SUCCESS): RespMsgUtil.returnMsg(RespEnum.ERROR);
	}
	/** 
	 * 进入修改页面
	 **/
	@RequestMapping("/toUpdate")
	public String toUpdate(Model model, Long id) {
		RedisModel entity = redisService.selectById(id);
		model.addAttribute("entity", entity);
		return "redis/update";
	}
	/** 
	 * 修改
	 **/
	@RequestMapping("/update")
	@ResponseBody
	public RespMsg update(HttpServletRequest request, HttpServletResponse response, RedisModel entity) {
		boolean isOK = redisService.updateById(entity);
		return isOK?RespMsgUtil.returnMsg(RespEnum.SUCCESS): RespMsgUtil.returnMsg(RespEnum.ERROR);
	}
	/** 
	 * 删除
	 **/
	@RequestMapping("/delete")
	@ResponseBody
	public RespMsg delete(HttpServletRequest request, HttpServletResponse response, Long id) throws Exception {
		boolean isOK = redisService.deleteById(id);
		return isOK?RespMsgUtil.returnMsg(RespEnum.SUCCESS): RespMsgUtil.returnMsg(RespEnum.ERROR);
	}
	/** 
	 * 查看详情
	 **/
	@RequestMapping("/show")
	public String delete(HttpServletRequest request, HttpServletResponse response, Model model, Long id) throws Exception {
		RedisModel entity = redisService.selectById(id);
		model.addAttribute("entity", entity);
		return "redis/show";
	}
}
